﻿@using System.Globalization;
@using System.Web.WebPages.Scope;
@using System.Xml.Linq;
@using System.Web.WebPages;

@functions {
    private const string InitializedExceptionMessage = "The Scribd Helper has not been initialized.";
    private const string ArgumentNullExceptionMessage = "Argument cannot be null or empty.";
    private const string NoDescriptionMessage = "No description available.";

    private static readonly object _apiKey = new object();
    private static readonly object _initializedKey = new object();

    public static string ApiKey {
		get {
			if (!Initialized) {
				throw new InvalidOperationException(InitializedExceptionMessage);
			}
			return (string)(ScopeStorage.CurrentScope[_apiKey] ?? "");
		}

		private set {
			if (value == null) {
				throw new ArgumentNullException("ApiKey");
			}

			ScopeStorage.CurrentScope[_apiKey] = value;
		}
	}
    
	private static bool Initialized {
		get {
			return (bool)(ScopeStorage.CurrentScope[_initializedKey] ?? false);
		}
		set {
			ScopeStorage.CurrentScope[_initializedKey] = value;
		}
	}

    /// <summary>
    /// Initializes the Scribd helper.
    /// </summary>
    /// <param name="apiKey">The API key assigned to your account.</param>
	public static void Initialize(string apiKey) {
		 if (apiKey.IsEmpty()) {
                throw new ArgumentException(ArgumentNullExceptionMessage, "apiKey");
         }

		ApiKey = apiKey;

		Initialized = true;
	}
    
    /// <summary>
    /// Retrieves the list of Scribd featured documents (for all users).
    /// </summary>
    /// <param name="limit">Number of results to return: Default 20, max 1000.</param>
    /// <param name="offset">Number to start at: Default 0. Cannot exceed 1000.</param>
    /// <param name="scope">Whether to search "new" documents or "hot" only. Set to "hot" by default.</param>
    public static IList<Document> GetFeaturedDocuments(
                                            int limit = 20,
                                            int offset = 0,
                                            string scope = "hot") {

        var url = string.Format(CultureInfo.InvariantCulture,
                                @"http://api.scribd.com/api?method=docs.featured&api_key={0}&limit={1}&offset={2}&scope={3}",
                                ApiKey, limit, offset, scope);
        var result = XElement.Load(url);

        CheckResultStatus(result);

        return result.Descendants("result").Select(d => CreateDocument(d)).ToList();
	}

    /// <summary>
    /// Retrieves a list of the user's documents.
    /// </summary>
    /// <param name="limit">Number of results to return: Default 20, max 1000.</param>
    /// <param name="offset">Number to start at: Default 0. Cannot exceed 1000.</param>
    public static IList<Document> GetUserDocuments(
                                            int limit = 20,
                                            int offset = 0) {

        var url = string.Format(CultureInfo.InvariantCulture,
                                @"http://api.scribd.com/api?method=docs.getList&api_key={0}&limit={1}&offset={2}",
                                ApiKey, limit, offset);
        var result = XElement.Load(url);

        CheckResultStatus(result);

        return result.Descendants("result").Select(d => CreateDocument(d)).ToList();
	}

    /// <summary>
    /// Retrieves a URL to the thumbnail of a document, in a given size.
    /// </summary>
    /// <param name="documentId">The ID of the document.</param>
    /// <param name="width">Width in pixels of the desired image.</param>
    /// <param name="height">Height in pixels of the desired image.</param>
    public static string GetThumbnailUrl(int documentId, int width = 129, int height = 167) {
        var url = string.Format(CultureInfo.InvariantCulture,
                                @"http://api.scribd.com/api?method=thumbnail.get&api_key={0}&doc_id={1}&width={2}&height={3}",
                                ApiKey, documentId, width, height);
        var result = XElement.Load(url);

        CheckResultStatus(result);
        
        return result.Element("thumbnail_url").Value;
	}

    private static void CheckResultStatus(XElement result) {
        if (string.Equals(result.Attribute("stat").Value, "fail", StringComparison.InvariantCultureIgnoreCase)) {
            var errorCode = result.Element("error").Attribute("code").Value;
            var errorMessage = result.Element("error").Attribute("message").Value;
            throw new ScribdException(string.Format(CultureInfo.InvariantCulture, "{0} - {1}", errorCode, errorMessage));
        }
    }
    
    private static Document CreateDocument(XElement e) {
        var document = new Document();

        document.DocId = int.Parse(e.Element("doc_id").Value);
        document.AccessKey = e.Element("access_key").Value;
        document.Title = e.Element("title").Value;
        document.Description = !e.Element("description").Value.IsEmpty() ? e.Element("description").Value : NoDescriptionMessage;
        document.ThumbnailUrl = e.Element("thumbnail_url").Value;
        document.Tags = e.Element("tags") != null ? e.Element("tags").Value.Split(',') : new string[0];
        document.License = e.Element("license") != null ? e.Element("license").Value : "";
        document.PageCount = int.Parse(e.Element("page_count").Value);
        document.DownloadFormats = e.Element("download_formats") != null ? e.Element("download_formats").Value.Split(',') : new string[0];
        document.Reads = e.Element("reads") != null ? e.Element("reads").Value.AsInt() : 0;
        document.UploadedBy = e.Element("uploaded_by") != null ? e.Element("uploaded_by").Value : "";
        document.WhenUploaded = DateTime.Parse(e.Element("when_uploaded").Value, CultureInfo.InvariantCulture);
        document.WhenUpdated = DateTime.Parse(e.Element("when_updated").Value, CultureInfo.InvariantCulture);

        return document;
    }
    
    private static string GetSummary(string text, int numberWords) {
        if (text.IsEmpty()) {
            return "";
        }

        var summary = FirstWords(text, numberWords);
        if (summary.Length < text.Length) {
            summary = string.Concat(summary, " ...");
        }

        return summary;
    }
    
    private static string FirstWords(string expression, int numberWords) {
        var words = numberWords;

        if (expression.IsEmpty()) {
            return "";
        }

        for (int i = 0; i < expression.Length; i++) {
            if (expression[i] == ' ') {
                words--;
            }

            if (words == 0) {
                return expression.Substring(0, i);
            }
        }

        return expression;
    }

    public class Document {
        public int DocId { get; set; }
        public String AccessKey { get; set; }
        public String Title { get; set; }
        public String Description { get; set; }
        public String DescriptionSummary { get { return GetSummary(this.Description, 35); }}
        public String ThumbnailUrl { get; set; }
        public String[] Tags { get; set; }
        public String License { get; set; }
        public int PageCount { get; set; }
        public String[] DownloadFormats { get; set; }
        public int Reads { get; set; }
        public String UploadedBy { get; set; }
        public DateTime WhenUploaded { get; set; }
        public DateTime WhenUpdated { get; set; }
	}

    public class ScribdException : Exception {
        public ScribdException(string message)
            : base(message) {
        }
    }
}
   
@helper GetDocumentList(dynamic documents,                        
                        int pageSize = 5) {
    
    var grid = new WebGrid(documents, rowsPerPage: pageSize);
    
    <link href="@Href("~/Scribd/Content/Styles.css")" rel="stylesheet" />          
    @grid.GetHtml(tableStyle: "docsTable",
                        columns: grid.Columns(
                                    grid.Column(style: "thumbnail_col", format: @<text><div class="thumbnail_shadow" style="width:131px;"><div class="thumbnail" style="height:167px;"><img title="" alt="@item.Title" src="@Scribd.GetThumbnailUrl(item.DocId, width: 129, height: 167)" /></div></div></text>),
                                    grid.Column(format: @<text>
                                                            <h3>@item.Title</h3>
                                                            <p class="doc_description">@if(!String.IsNullOrEmpty(item.UploadedBy)) { <span class="uploaded_by">Uploaded by: </span><span class="author">@item.UploadedBy</span> <span>&mdash;</span> }@item.DescriptionSummary</p>
                                                            <dl class="doc_info">
                                                                <dt>Reads:</dt><dd>@item.Reads</dd>
                                                                <dt>Uploaded:</dt><dd>@item.WhenUploaded.ToShortDateString()</dd>
                                                            </dl>                                                            
                                                            <a class="read_button" title="Read this Document" href="javascript:showReader(@item.DocId, '@item.AccessKey', '@item.Title');">Read this Document</a>
                                                        </text>)
                        ))

    <script type="text/javascript" src="http://ajax.microsoft.com/ajax/jquery/jquery-1.4.2.min.js"></script> 
    <script type="text/javascript" src="http://ajax.microsoft.com/ajax/jquery.ui/1.8.5/jquery-ui.min.js"></script>
    <link rel="Stylesheet" type="text/css" href="http://ajax.microsoft.com/ajax/jquery.ui/1.8.5/themes/ui-darkness/jquery-ui.css" /> 
    
    <script type='text/javascript' src='http://www.scribd.com/javascripts/view.js'></script>
    
    <div id="reader_dialog" style="display: none;">       
        <div id='embedded_flash'>
            <a href="http://www.scribd.com">Scribd</a>
        </div>
    </div>    

    <script type="text/javascript">
        function showReader(docId, accessKey, title) {
            var scribd_doc = scribd.Document.getDoc(docId, accessKey);
    
            scribd_doc.addParam('jsapi_version', 1);
            scribd_doc.addParam('width', 500);
            scribd_doc.addParam('height', 570);
            
            scribd_doc.write('embedded_flash');
            
            $("#reader_dialog").dialog({
			    modal: true,
                resizable: false,
                title: title,
                width: 530,
                height: 630
		    });
        }
    </script>
}
                        
@*
Summary:
    Displays a widget that lists the Scribd featured documents. It allows the user to read the document by using the Scribd reader.

Parameter: limit
    Number of results to return: Default 20, max 1000.

Parameter: offset
    Number to start at: Default 0. Cannot exceed 1000.

Parameter: scope
    Whether to search "new" documents or "hot" only. Set to "hot" by default.

Parameter: pageSize
    Number of results to display per page.

Returns:
    An HTML table with featured documents.
*@  
@helper GetFeaturedDocumentsWidget(int limit = 20,
                                   int offset = 0,
                                   string scope = "hot",
                                   int pageSize = 5) {
    
    var documents = GetFeaturedDocuments(limit, offset, scope); 
    
    @GetDocumentList(documents, pageSize)
}

@*
Summary:
    Displays a widget that lists the user's documents.. It allows the user to read the document by using the Scribd reader.

Parameter: limit
    Number of results to return: Default 20, max 1000.

Parameter: offset
    Number to start at: Default 0. Cannot exceed 1000.

Parameter: pageSize
    Number of results to display per page.

Returns:
    An HTML table with featured documents.
*@  
@helper GetUserDocumentsWidget(int limit = 20,
                               int offset = 0,                                
                               int pageSize = 5) {
    
    var documents = GetUserDocuments(limit, offset); 
    
    @GetDocumentList(documents, pageSize)
}